home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
System Booster
/
System Booster.iso
/
Systemmonitors
/
PriMan
/
Source
/
Util.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-09-26
|
30KB
|
1,113 lines
/*
* Task Priority Manager
* Copyright 1993, 1994 Barry McConnell
* bmccnnll@tcd.ie
*
* A library of little functions called from within the main program,
* sorted alphabetically.
*
* Set tab stops to 4 when editing this file.
*/
#include "PriMan.h"
/*
* My version of sprintf requires this define, for the function passed to
* RawDoFmt(). Thanks to Eddy Carroll & SnoopDos for this...
*/
#define RAWDOFMT_COPY (void (*))"\x16\xc0\x4e\x75" /* MOVE.B D0,(A3)+ ; RTS */
/*
* The BusyPointer() and NormalPointer() functions rely on these requester
* structures. By declaring them as static, they aren't visible outside
* this file and the calling functions need not worry about them.
*/
static struct Requester req1, req2;
/*
* It is possible that BusyPointer() might be called twice (or more) in
* succession, by some code that doesn't realise one is already up. So we
* use a variable (again only visible to this file) to say how many times
* it has been called. Only the first time round do we actually put up the
* busy pointer (the system will crash if we try to re-use the blocking
* requester structure).
*
* When NormalPointer() is called, the variable is decremented. Only once
* it gets back down to zero do we restore the pointer.
*/
static int busyCount;
/*
* This is an image of the standard Busy pointer, which the BusyPointer()
* function uses when not running under V39.
*/
UWORD __chip waitPointer[] =
{
0x0000, 0x0000,
0x0400, 0x07c0,
0x0000, 0x07c0,
0x0100, 0x0380,
0x0000, 0x07e0,
0x07c0, 0x1ff8,
0x1ff0, 0x3fec,
0x3ff8, 0x7fde,
0x3ff8, 0x7fbe,
0x7ffc, 0xff7f,
0x7efc, 0xffff,
0x7ffc, 0xffff,
0x3ff8, 0x7ffe,
0x3ff8, 0x7ffe,
0x1ff0, 0x3ffc,
0x07c0, 0x1ff8,
0x0000, 0x07e0,
0x0000, 0x0000,
};
/*
* Display a busy pointer in both windows, and prevent the user from
* clicking on any gadgets. Also effectively disable the size gadget.
* We are careful to make sure that each window is actually open before
* putting up a busy pointer in it, and also that there isn't already a
* busy pointer showing!
*/
void BusyPointer()
{
if (++busyCount == 1)
{
if (mainWindow)
{
/*
* To disable the size gadget, we make the minimum and maximum window
* dimensions equal to the current window dimensions.
*/
WindowLimits(mainWindow, mainWindow -> Width, mainWindow -> Height,
mainWindow -> Width, mainWindow -> Height);
/*
* To disable the main window's gadgets, we put up an invisible
* "blocking requester".
*/
Request(&req1, mainWindow);
/*
* There are two different ways of putting up a busy pointer, depending
* on which OS version we're running under.
*/
if (osver < 39)
SetPointer(mainWindow, waitPointer, 16, 16, -6, 0);
else
SetWindowPointer(mainWindow, WA_BusyPointer, TRUE,
WA_PointerDelay, TRUE,
TAG_END);
}
/*
* The exact same things are done for the Settings window (except we
* don't need to worry about the size gadget!).
*/
if (setWindow)
{
Request(&req2, setWindow);
if (osver < 39)
SetPointer(setWindow, waitPointer, 16, 16, -6, 0);
else
SetWindowPointer(setWindow, WA_BusyPointer, TRUE,
WA_PointerDelay, TRUE,
TAG_END);
}
}
}
/*
* Close the main window if it's open, freeing up its gadgets and menus if
* necessary. Also remember its position and dimensions in case we later
* want to re-open it.
*/
void CloseMainWindow()
{
if (mainWindow)
{
if (menuStrip)
{
ClearMenuStrip(mainWindow);
FreeMenus(menuStrip);
}
GetPos();
CloseWindowSafely(mainWindow);
mainWindow = NULL;
}
FreeGadgets(mainGads);
mainGads = NULL;
/*
* Chances are we will also have opened some fonts. We close them here,
* and then free up the VisualInfo structure, as well as releasing our
* lock on the screen.
*/
if (propFont)
{
CloseFont(propFont);
propFont = NULL;
}
if (monoFont)
{
CloseFont(monoFont);
monoFont = NULL;
}
if (visInfo)
{
FreeVisualInfo(visInfo);
visInfo = NULL;
}
if (myScreen)
{
UnlockPubScreen(NULL, myScreen);
myScreen = NULL;
}
}
/*
* Close the settings window if it's open. It's tricky to free up any
* attached gadgets, since the last gadget in the list of gadgets pointed
* to by setGads[3] (the Page gadget, and the buttons at the bottom of the
* window) may have been modified to point to one of the other gadget
* lists, depending on what is showing. So we first remove the "other"
* gadget list (using the page variable to see what it is) which should
* sever the link, before freeing each individual list. It should never
* happen that the Settings window is open without a second set of gadgets
* in it, but even if this occurs, RemoveGList() won't mind if it doesn't
* find them.
*/
void CloseSettingsWindow()
{
int i; /* page number */
if (setWindow)
{
RemoveGList(setWindow, setGads[page], -1);
CloseWindowSafely(setWindow);
setWindow = NULL;
}
for (i = 0; i < 4; i++)
{
FreeGadgets(setGads[i]);
setGads[i] = NULL;
}
}
/*
* Safely close a window that might have a shared IDCMP. This is done by
* removing all messages from the window's MsgPort that refer to the
* window. (We can't just remove every message, in case some of them are
* actually meant for another window with the same IDCMP.)
*/
void CloseWindowSafely(struct Window *window)
{
struct IntuiMessage *msg; /* message in window's port */
struct Node *succ; /* next message */
/*
* First we need to disable multitasking, so we don't run into race
* conditions with Intuition.
*/
Forbid();
/*
* Next we get a pointer to the first message in the window's MsgPort.
*/
msg = (struct IntuiMessage *)window -> UserPort -> mp_MsgList.lh_Head;
/*
* We loop around until we reach the last message.
*/
while (succ = msg -> ExecMessage.mn_Node.ln_Succ)
{
if (msg -> IDCMPWindow == window)
{
/*
* Once we have a message destined for this window, we remove
* it from the MsgPort, and reply to it.
*/
Remove((struct Node *)msg);
ReplyMsg((struct Message *)msg);
}
/*
* "msg" will be invalid if it was freed above, which is why we
* took a copy of its successor at the start of the loop.
*/
msg = (struct IntuiMessage *)succ;
}
/*
* When we close the window, we don't want Intuition to free up the
* MsgPort itself (in case another window uses it too), so we remove
* all traces of it here. We also set the window's IDCMP to NULL so
* Intuition doesn't try sending it any more messages.
*/
window -> UserPort = NULL;
ModifyIDCMP(window, NULL);
/*
* Finally we can re-enable multitasking, and close the window safely.
*/
Permit();
CloseWindow(window);
}
/*
* Compare two strings. Like strcmp() but case-insensitive.
*/
int Compare(char *s, char *t)
{
/*
* This bit is tricky. The loop only continues as long as:
*
* - The upper-case versions of the current character in each string
* match, and;
*
* - The current character in the first string is not NULL (if we have
* reached a NULL in the second string instead, the first condition
* above would not hold true!);
*
* (Okay, so I could have used K&R's slightly lengthier version...)
*/
for (; ((*s & ~32) == (*t & ~32)) && *s; s++, t++)
; /* empty body */
/*
* To be true to the original strcmp() function, we return:
*
* - Zero if the strings match (in this case, we will have reached the
* end of both strings, and subtracting the NULL terminators gives
* zero), or;
*
* - A positive or negative number, indicating which string is
* alphabetically greater.
*/
return (*s & ~32) - (*t & ~32);
}
/*
* Stub for Compare() which is used when inserting tasks into the task
* list. This skips over opening brackets (for frozen tasks) in either
* string.
*/
int CompareTasks(char *s, char *t)
{
if (*s == '(')
s++;
if (*t == '(')
t++;
return Compare(s, t);
}
/*
* Tiny function to draw the bevel box in the Settings window.
*/
void DrawSettingsBox()
{
DrawBevelBox(setWindow -> RPort, INTERWIDTH, setGadStart - INTERHEIGHT,
setWindow -> Width - INTERWIDTH * 2, setGadHeight + INTERHEIGHT * 2,
GTBB_Recessed, TRUE,
GT_VisualInfo, visInfo,
TAG_END);
}
/*
* Join together a font name and its size. The characters in the font name up
* to the ".font" part are used.
*/
void FontString(struct TextAttr *font, char *dest)
{
int i = 0; /* index into font name */
while ((font -> ta_Name)[i] != '.')
*(dest++) = (font -> ta_Name)[i++];
sprintf(dest, " %ld", font -> ta_YSize);
}
/*
* Check if a task has been frozen. Just looks at the State field and
* compares against our two possible frozen states.
*/
BOOL Frozen(struct Task *task)
{
switch (task -> tc_State)
{
case FROZEN:
case FROZENREADY:
return TRUE;
break;
default:
return FALSE;
break;
}
}
/*
* Remember the top entry in the ListView (used before regenerating it).
* Under 2.x the best we can do is assume the top entry is the currently-
* selected entry, but under 3.x we can find out exactly what it is.
*/
void GetListTop()
{
if (osver < 39)
{
if (current)
top = pos;
else
top = 0;
}
else
GT_GetGadgetAttrs(listGad, mainWindow, NULL,
GTLV_Top, &top,
TAG_END);
}
/*
* Remember the co-ordinates of the main window (used before closing it).
*/
void GetPos()
{
if (mainWindow)
{
winLeft = mainWindow -> LeftEdge;
winTop = mainWindow -> TopEdge;
winWidth = mainWindow -> Width;
winHeight = mainWindow -> Height;
}
}
/*
* Fire up the AmigaGuide file - this is PriMan's online help feature. If
* we have not already opened amigaguide.library, we should do so now, and
* refuse to continue if it's not around.
*/
void Help()
{
static struct Screen *guideScreen; /* screen we're open on now */
struct EasyStruct noHelp =
{
sizeof(struct EasyStruct),
0,
"PriMan warning",
"Can't open amigaguide.library -\nno online help available.",
"Okay"
};
if (!AmigaGuideBase)
if (!(AmigaGuideBase = OpenLibrary("amigaguide.library", 34)))
{
SimpleRequest(&noHelp, NULL);
return;
}
/*
* If this is the first time the user has asked for help, we tell
* AmigaGuide to open the PriMan.guide file (which the user must have
* placed either in the current directory or in the AmigaGuide search
* path), note its signal bit (it uses one of our task's free signal
* bits), and then return. PriMan's main loop listens for AmigaGuide
* messages, and once it gets one that says AmigaGuide has finished
* opening the file and is ready for further instructions, this
* function is called again, and the next section of code is used
* instead which actually opens the window...
*/
if (!guideHandle)
{
/*
* If PriMan's main window is not open (i.e. this is being called
* as a result of a "?" argument from the Shell), then we won't
* have a lock on any screen. In this case we check (but not lock)
* whatever screen the user asked for in the settings, and open on
* that. Otherwise we simply use the current screen. We always move
* the chosen screen to the front in case it isn't already visible.
*/
guideScreen = myScreen ? myScreen : LockOurScreen(FALSE);
myGuide.nag_Screen = guideScreen;
myGuide.nag_Name = "PriMan.guide";
if (guideHandle = OpenAmigaGuideAsync(&myGuide, NULL))
{
guideSignal = AmigaGuideSignal(guideHandle);
ScreenToFront(guideScreen);
}
}
/*
* The next alternative is that AmigaGuide is silently sitting in the
* background with PriMan.guide loaded. Unless the main PriMan window
* is not open (myScreen is null), we check if the AmigaGuide screen is
* the same, and if it is, just ask AmigaGuide to display the first
* node (Main). If the user has closed the AmigaGuide window himself,
* or it hasn't been opened yet, this will have the effect of opening
* the window. Otherwise, it will stay open and the first node will be
* shown.
*/
else if (!myScreen || guideScreen == myScreen)
SendAmigaGuideCmd(guideHandle, "LINK Main", NULL);
/*
* If we got here, AmigaGuide is running on the wrong screen. So we
* close it down and call Help() again, taking us right back to square
* one...
*/
else
{
CloseAmigaGuide(guideHandle);
guideHandle = 0;
guideSignal = 0;
Help();
}
}
/*
* This closes down PriMan's interface, freeing up everything and
* iconifying if necessary. If we're not running as a Commodity and can't
* be iconified, it asserts the "all okay" error condition (which itself
* will take care of freeing everything).
*/
void Hide()
{
if (!(iconify || commodity))
error = ALL_OKAY;
else
{
CloseSettingsWindow();
CloseMainWindow();
FreeRemember(&memoryKey, TRUE);
Iconify();
}
}
/*
* This tiny function adds PriMan's AppIcon to Workbench, if necessary.
* For want of something better, we'll assign it an ID of 42...
*/
void Iconify()
{
if (iconify)
appIcon = AddAppIcon(42, NULL, "PriMan", appPort, NULL, wbIcon, TAG_END);
}
/*
* Get a lock on the screen we should be open on now. Opening on the
* default public screen is easy (just pass a NULL to the lock function),
* but opening on the frontmost screen is tricky (it might not even be a
* public screen!). To achieve this, we walk through the public screen list
* trying to find a match for what Intuition says its frontmost screen is.
* If we can't find one, we open on the default public screen. If that
* fails, we open on the Workbench screen. (And as Eddy says, if _that_
* fails, then we're really screwed!)
*
* If this function is only being used to check where we *should* be, pass
* in FALSE to unlock the screen and just get back a pointer to what it was
* (no guarantees that it won't have closed in the meantime!).
*/
struct Screen *LockOurScreen(BOOL keepLock)
{
char *screenName; /* name of matching screen */
struct List *pubList; /* Intuition's list of public screens */
struct Screen *screen; /* frontmost screen which we're looking for */
struct PubScreenNode *pubNode; /* current screen being examined in list */
/*
* We set screenName to NULL here, in the assumption that we'll be
* opening on the default public screen. This only gets changed if we
* want to open on the frontmost screen, and it is found in the public
* screen list.
*/
screenName = NULL;
if (open == FRONTSCREEN)
{
pubList = LockPubScreenList();
screen = IntuitionBase -> FirstScreen;
FORLIST(pubList, pubNode)
if (pubNode -> psn_Screen == screen)
{
screenName = pubNode -> psn_Node.ln_Name;
break; /* found it, so drop out of loop */
}
UnlockPubScreenList();
}
/*
* At this point, if screenName is NULL, then it is either because we
* want to open on the default public screen, or because we didn't find
* a match when walking through the public screen list. We try to lock
* whatever it points to, and if that fails, lock the Workbench screen
* as a last resort.
*/
if (!(screen = LockPubScreen(screenName)))
screen = LockPubScreen("Workbench");
/*
* If the caller just wants to see what screen PriMan *should* be open
* on, we unlock it here.
*/
if (!keepLock)
UnlockPubScreen(NULL, screen);
return screen;
}
/*
* Add "..." after the Kill and Signal menu items as necessary. If reset
* is TRUE, remove the menu strip from the main window first. The menu
* strip gets rejigged appropriately and added back into the window.
*/
void MenuEllipsis(struct Menu *menuStrip, BOOL reset)
{
static UBYTE *kill, *signal; /* pointers to Kill and Signal menu item text */
if (reset)
ClearMenuStrip(mainWindow);
if (confirm)
{
kill = "Kill...";
signal = "Signal...";
}
else
{
kill = "Kill";
signal = "Signal";
}
((struct IntuiText *)ItemAddress(menuStrip, FULLMENUNUM(M_TASK, I_KILL, NOSUB)) -> ItemFill) -> IText = kill;
((struct IntuiText *)ItemAddress(menuStrip, FULLMENUNUM(M_TASK, I_SIGNAL, NOSUB)) -> ItemFill) -> IText = signal;
if (LayoutMenus(menuStrip, visInfo,
GTMN_NewLookMenus, TRUE,
TAG_END))
SetMenuStrip(mainWindow, menuStrip);
else
error = MENU_ERROR;
}
/*
* Put up a different gadget list in the Settings window. Uses the page
* variable to see what is currently showing (or -1 if nothing). If this is
* the same as what is being asked for, we don't need to do anything.
* Otherwise, remove the old gadget list, replace it with the new one, and
* update the page variable.
*/
void NewPage(WORD newPage)
{
if (page != newPage)
{
if (page != -1)
{
/*
* If there was something showing already, we need to remove
* those gadgets, and blank that portion of the window.
*/
RemoveGList(setWindow, setGads[page], -1);
blank.Width = setWindow -> Width - INTERWIDTH * 4;
blank.Height = setGadHeight;
EraseImage(setWindow -> RPort, &blank, INTERWIDTH * 2, setGadStart);
}
page = newPage;
AddGList(setWindow, setGads[page], ~0, -1, NULL);
RefreshGList(setGads[page], setWindow, NULL, -1);
GT_RefreshWindow(setWindow, NULL);
}
}
/*
* Restore the pointer to normal, enabling gadgets and window sizing. This
* essentially reverses everything done in BusyPointer(). We don't do
* anything if there are more pending calls to NormalPointer().
*/
void NormalPointer()
{
if (--busyCount == 0)
{
if (mainWindow)
{
ClearPointer(mainWindow);
EndRequest(&req1, mainWindow);
WindowLimits(mainWindow, minWidth, minHeight, ~0, ~0);
}
if (setWindow)
{
ClearPointer(setWindow);
EndRequest(&req2, setWindow);
}
}
}
/*
* This tiny function is used whenever a task gets deselected. It simply
* disables the Kill, Priority, Signal, Frozen and Wide Slider menu items,
* as well as invalidating pos.
*/
void OffTask()
{
OffMenu(mainWindow, FULLMENUNUM(M_TASK, I_KILL, NOSUB));
OffMenu(mainWindow, FULLMENUNUM(M_TASK, I_PRIORITY, NOSUB));
OffMenu(mainWindow, FULLMENUNUM(M_TASK, I_SIGNAL, NOSUB));
OffMenu(mainWindow, FULLMENUNUM(M_TASK, I_FROZEN, NOSUB));
OffMenu(mainWindow, FULLMENUNUM(M_TASK, I_WIDE, NOSUB));
pos = -1;
}
/*
* This function is used whenever a task gets selected. It updates the
* slider gadget to reflect the task's priority, sets it to the correct
* scale, and enables the Kill, Priority, Signal, Frozen and (if
* appropriate) Wide Slider menu items.
*/
void OnTask()
{
struct MenuItem *item; /* Wide Slider menu item */
/*
* First we want to temporarily remove the menu strip, and get the
* address of the Wide Slider menu item. The menu strip gets put back
* after updating the menu item.
*/
ClearMenuStrip(mainWindow);
item = ItemAddress(menuStrip, FULLMENUNUM(M_TASK, I_WIDE, NOSUB));
if (current -> ln_Pri > -26 && current -> ln_Pri < 26)
{
/*
* We can use a narrow scale, so reset the menu's
* checkmark, enable the menu item (allowing the user
* to move to a wide scale), then update the slider
* gadget's scale.
*/
item -> Flags &= ~CHECKED;
item -> Flags |= ITEMENABLED;
WideSlider(FALSE);
}
else
{
/*
* We're forced into using a wide scale. Set the menu's
* checkmark but don't allow the user to change it!
*/
item -> Flags |= CHECKED;
item -> Flags &= ~ITEMENABLED;
WideSlider(TRUE);
}
ResetMenuStrip(mainWindow, menuStrip);
/*
* Now we change the value of the slider gadget.
*/
GT_SetGadgetAttrs(sliderGad, mainWindow, NULL,
GTSL_Level, current -> ln_Pri,
GA_Disabled, FALSE,
TAG_END);
/*
* And finally, we make sure the appropriate menu items are enabled.
*/
OnMenu(mainWindow, FULLMENUNUM(M_TASK, I_KILL, NOSUB));
OnMenu(mainWindow, FULLMENUNUM(M_TASK, I_PRIORITY, NOSUB));
OnMenu(mainWindow, FULLMENUNUM(M_TASK, I_SIGNAL, NOSUB));
OnMenu(mainWindow, FULLMENUNUM(M_TASK, I_FROZEN, NOSUB));
}
/*
* Simulate a gadget being pressed (when the keyboard shortcut is used).
* The gadget is marked as "selected", there is a delay, and then it is put
* back to normal again.
*/
void PressGadget(struct Window *window, struct Gadget *gadget)
{
gadget -> Flags ^= GFLG_SELECTED;
RefreshGList(gadget, window, NULL, 1);
Delay(PressDelay);
gadget -> Flags ^= GFLG_SELECTED;
RefreshGList(gadget, window, NULL, 1);
}
/*
* Make sure a variable lies within the specified range, by increasing or
* decreasing it if necessary. Used to keep the main window's size inside
* acceptable limits.
*/
void Range(WORD *current, WORD min, WORD max)
{
if (*current < min)
*current = min;
else if (*current > max)
*current = max;
}
/*
* Request a font from the user. This function handles both the Gadget and
* List font requesters, and initialises them beforehand if necessary. It
* takes in the parameters below, and returns the result of AslRequest(),
* after updating the Settings window's font box and related variables.
*
* mainReq pointer to a pointer of the requester to be used
* otherReq pointer to the other requester
* initialName name of the initially-selected font in the requester
* initialSize pointer to the size of that font
* fontGadget the text box showing the selected font's name
* fontString the font name and size inside that text box
* title title of the requester's window
* flags flags to be passed (either zero or the fixed-width flag)
*/
BOOL RequestFont(struct FontRequester **mainReq, struct FontRequester *otherReq,
char *initialName, WORD *initialSize,
struct Gadget *fontGadget, char *fontString,
char *title, ULONG flags)
{
ULONG reqTag; /* says whether or not we're using width tag */
WORD reqWidth, /* initial width of requester */
reqHeight; /* initial height of requester */
BOOL result; /* return value from AslRequest() */
BusyPointer();
/*
* If this is the first time the user has played with the requester, we
* need to allocate memory for it, and initialise it. We do this now
* (rather than when PriMan is first launched) so we can make a good
* guess at what height is best. If the other requester has been opened
* before, we use its height and width, otherwise we use 2/3 of the
* screen's height and the default width.
*/
if (!*mainReq)
{
if (otherReq)
{
reqHeight = otherReq -> fo_Height;
reqWidth = otherReq -> fo_Width;
reqTag = ASLFO_InitialWidth;
}
else
{
reqHeight = myScreen -> Height * 2 / 3;
reqWidth = 0; /* not strictly needed since it's ignored */
reqTag = TAG_IGNORE;
}
*mainReq = AllocAslRequestTags(ASL_FontRequest,
ASLFO_TitleText, title,
ASLFO_InitialHeight, reqHeight,
reqTag, reqWidth,
ASLFO_Flags, flags,
TAG_END);
}
/*
* The requester gets offset from the Settings window in
* same way as the Settings window gets offset from the
* main window (by the dimensions of the close gadget).
*/
if (result = AslRequestTags(*mainReq,
ASLFO_Screen, myScreen,
ASLFO_TextAttr, &propTA, /* use gadget font for imagery */
ASLFO_InitialLeftEdge, setWindow -> LeftEdge + CloseBoxWidth,
ASLFO_InitialTopEdge, setWindow -> TopEdge + windowTop,
ASLFO_InitialName, initialName,
ASLFO_InitialSize, *initialSize,
TAG_END))
{
/*
* Here we update the font text box in the Settings window, and
* copy the font information from the requester. (This doesn't
* happen if the user clicked Cancel.)
*/
FontString(&((*mainReq) -> fo_Attr), fontString);
GT_SetGadgetAttrs(fontGadget, setWindow, NULL,
GTTX_Text, fontString,
TAG_END);
strcpy(initialName, (*mainReq) -> fo_Attr.ta_Name);
*initialSize = (*mainReq) -> fo_Attr.ta_YSize;
}
NormalPointer();
return result;
}
/*
* Set up the Commodity interface. This involves creating a broker, and
* attaching to it a filter, sender and translator.
*/
void SetupCommodity()
{
LONG brokerError; /* error returned when creating a new broker */
/*
* This is the error requester in case something went wrong when setting up
* the Commodity's hotkey.
*/
struct EasyStruct badFilter =
{
sizeof(struct EasyStruct),
0,
"PriMan warning",
"Invalid hotkey - suggest you change it.",
"Okay"
};
if (broker = CxBroker(&newBroker, &brokerError))
{
/*
* Create the filter, which monitors input events for our hotkey.
*/
if (filter = CxFilter(hotkey))
{
AttachCxObj(broker, filter);
/*
* Create the sender, which sends a message to our port once
* the hotkey is spotted.
*/
if (sender = CxSender(cxPort, 1))
{
AttachCxObj(filter, sender);
/*
* Create the translator. This one is a dummy translator,
* and simply removes the hotkey from the input stream, so
* no other application can use it.
*/
if (translate = CxTranslate(NULL))
{
AttachCxObj(filter, translate);
ActivateCxObj(broker, 1);
if (CxObjError(filter) == COERR_BADFILTER)
SimpleRequest(&badFilter, NULL);
}
else
error = CX_ERROR;
}
else
error = CX_ERROR;
}
else
error = CX_ERROR;
}
else
/*
* Here, there are two possibilities:
*
* - A similar broker already exists. In this case, we silently
* shut down (and let the copy of PriMan which must already be
* running take control).
*
* - There was an error creating the broker. We do the same as when
* there was an error creating anything else above: raise the
* appropriate error condition.
*/
error = brokerError == CBERR_DUP ? ALL_OKAY : CX_ERROR;
}
/*
* Reveal PriMan's interface. There are several possibilities here:
*
* - No windows are showing. In this case, we remove the AppIcon if
* necessary, then simply open the main window.
*
* - The main window is open, but it's not on the correct screen. So we
* shut everything down and reopen, which will get us onto the correct
* screen. It is important to remember if the Settings window is open,
* so that can follow us around as well.
*
* - The main window is both open, and on the correct screen. All we need
* to do is move both the main window and its screen to the front, and
* the Settings window too if that's also open.
*/
void Show()
{
BOOL reopenSettings; /* Settings window was open when we jumped screen */
struct Screen *tempScreen; /* screen we should be on */
if (!mainWindow)
{
if (appIcon)
{
RemoveAppIcon(appIcon);
appIcon = NULL;
}
OpenMainWindow();
}
else
{
/*
* Check what screen we should be on, but don't actually lock it.
*/
tempScreen = LockOurScreen(FALSE);
if (tempScreen != myScreen)
{
reopenSettings = (setWindow != NULL);
CloseSettingsWindow();
CloseMainWindow();
OpenMainWindow();
if (reopenSettings)
OpenSettingsWindow();
}
else
{
WindowToFront(mainWindow);
if (setWindow)
{
WindowToFront(setWindow);
ActivateWindow(setWindow);
}
else
ActivateWindow(mainWindow);
ScreenToFront(myScreen);
}
}
}
/*
* Put up a busy pointer and open the requester passed into this function.
* If the requester structure requires further arguments, they can be
* passed in as well.
*/
LONG SimpleRequest(struct EasyStruct *easyReq, APTR args)
{
LONG result; /* return value from EasyRequest() */
BusyPointer();
result = EasyRequest(NULL, easyReq, NULL, args);
NormalPointer();
return result;
}
/*
* This version of sprintf uses the exec routine, courtesy of Eddy Carroll
* and SnoopDos. Saves pulling in a lot of unnecessary library routines.
* The only difference between this and the one in stdio is that this
* always returns 0 instead of the length of the string.
*/
int __regargs sprintf(char *outstr, char *fmtstr, ...)
{
RawDoFmt(fmtstr, &fmtstr + 1, RAWDOFMT_COPY, outstr);
return 0;
}
/*
* Increment or decrement a value, making sure it stays within 0..range.
* This is useful when using the keyboard shortcuts for a cycle gadget.
*/
WORD Step(WORD value, WORD range, UWORD decrement)
{
if (decrement)
{
value--;
if (value < 0)
value = range;
}
else
{
value++;
if (value > range)
value = 0;
}
return value;
}
/*
* Check to see if a task still exists. This works by checking the State
* field, and comparing against a list of valid states. Hence it is not
* 100% accurate (the task might not exist, but that particular byte of
* memory happens to be set the way we want it), but it'll have to do...
*/
BOOL ValidTask(struct Task *task)
{
switch (task -> tc_State)
{
case TS_RUN:
case TS_READY:
case TS_WAIT:
case FROZEN:
case FROZENREADY:
return TRUE;
break;
default:
return FALSE;
break;
}
}
/*
* Change the slider gadget's scale to wide or narrow.
*/
void WideSlider(BOOL wide)
{
if (wide)
GT_SetGadgetAttrs(sliderGad, mainWindow, NULL,
GTSL_Min, -128,
GTSL_Max, 127,
TAG_END);
else
GT_SetGadgetAttrs(sliderGad, mainWindow, NULL,
GTSL_Min, -25,
GTSL_Max, 25,
TAG_END);
}
/*
* Remove all remaining messages from a port, then delete it. Used when
* shutting down PriMan's message ports. We do this while multitasking is
* disabled, so no other messages can arrive in the meantime.
*/
void WipePort(struct MsgPort *port)
{
struct Message *message; /* current message in port */
Forbid();
while (message = GetMsg(port))
ReplyMsg(message);
DeleteMsgPort(port);
Permit();
}